import { Config, Inject, Provide } from '@midwayjs/decorator';
import { BaseService, CoolCommException } from '@cool-midway/core';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { In, Repository } from 'typeorm';
import * as jwt from 'jsonwebtoken';
import { BizCustomerListEntity } from '../entity/list';
import { BizCustomerWorkerCollectionEntity } from '../entity/workerCollection';
import { BizWorkerListEntity } from '../../bizWorker/entity/list';
import { BizWxService } from './wx';
import { randomInt } from '../../../comm/random';
import { formatDate } from '../../../comm/date';

/**
 * 顾客相关服务
 */
@Provide()
export class BizCustomerListService extends BaseService {
  @Inject()
  ctx;

  @Config('module.bizCustomer.jwt')
  jwtConfig;

  @InjectEntityModel(BizCustomerListEntity)
  bizCustomerListEntity: Repository<BizCustomerListEntity>;
  @InjectEntityModel(BizCustomerWorkerCollectionEntity)
  bizCustomerWorkerCollectionEntity: Repository<BizCustomerWorkerCollectionEntity>;
  @InjectEntityModel(BizWorkerListEntity)
  bizWorkerListEntity: Repository<BizWorkerListEntity>;

  @Inject()
  bizWxService: BizWxService;

  /**
   * 微信小程序登录
   * @param code
   * @param encryptedData
   * @param iv
   * @returns
   */
  async loginWxMiniApp(code: string, encryptedData: string, iv: string) {
    const session = await this.bizWxService.miniSession(code);
    const { errcode, errmsg, session_key, openid, unionid } = session;
    if (errcode) {
      throw new CoolCommException(`登录失败 ${errmsg}`);
    }
    const info: any = await this.bizWxService.miniDecryptData(
      encryptedData,
      iv,
      session_key
    );
    if (info) {
      /*
        phoneNumber 用户绑定的手机号（国外手机号会有区号）
        purePhoneNumber 没有区号的手机号
        countryCode 区号
        watermark 数据水印
          timestamp 用户获取手机号操作的时间戳
          appid 小程序appid
      */
      const { phoneNumber, purePhoneNumber, countryCode, watermark } = info;

      let userInfo: any = await this.bizCustomerListEntity.findOneBy({
        wechatOpenId: openid,
      });
      if (userInfo) {
        // 老用户
      } else {
        // 新用户
        const { generatedMaps } = await this.bizCustomerListEntity.insert({
          phone: purePhoneNumber,
          nickName: `佳西用户_${formatDate(
            new Date(),
            ''
          )}${randomInt()}${randomInt()}${randomInt()}${randomInt()}`,
          headPhoto: '',
          wechatOpenId: openid,
          status: 1,
        });
        userInfo = generatedMaps[0];
      }
      const { id } = userInfo;

      const result = {
        id,
        token: await this.token({ id }),
      };
      return result;
    } else {
      throw new CoolCommException(`登录失败，微信解密失败`);
    }
  }

  /**
   * 获得token
   * @param info
   * @returns
   */
  async token(info) {
    const { expire, refreshExpire } = this.jwtConfig;
    return {
      expire,
      token: await this.generateToken(info),
      refreshExpire,
      refreshToken: await this.generateToken(info, true),
    };
  }

  /**
   * 刷新token
   * @param refreshToken
   */
  async refreshToken(refreshToken) {
    try {
      const info = jwt.verify(refreshToken, this.jwtConfig.secret);
      if (!info['isRefresh']) {
        throw new CoolCommException('token类型非refreshToken');
      }
      const userInfo = await this.bizCustomerListEntity.findOneBy({
        id: info['id'],
      });
      return await this.token({
        id: userInfo.id,
      });
    } catch (e) {
      throw new CoolCommException(
        '刷新token失败，请检查refreshToken是否正确或过期'
      );
    }
  }

  /**
   * 生成token
   * @param tokenInfo 信息
   * @param roleIds 角色集合
   */
  async generateToken(info, isRefresh = false) {
    const { expire, refreshExpire, secret } = this.jwtConfig;
    const tokenInfo = {
      isRefresh,
      ...info,
    };
    return jwt.sign(tokenInfo, secret, {
      expiresIn: isRefresh ? refreshExpire : expire,
    });
  }

  /**
   * 获取用户收藏列表
   */
  async workerCollection(page: number, size: number, userId: number) {
    const workerIds = (
      await this.bizCustomerWorkerCollectionEntity.findBy({ userId })
    ).map(v => v.workerId);

    const workerIdPages = workerIds.slice(page - 1, page * size);

    const list = await this.bizWorkerListEntity.findBy({
      id: In(workerIdPages),
      status: 1,
    });

    return {
      list: list,
      pagination: {
        page: page,
        size: size,
        total: workerIds.length,
      },
    };
  }
}
